"""
Case Type   : cm
Case Name   : 异步备节点CMS服务和数据库服务同时异常停止
Create At   : 2024-07
Owner       : haomeng
Description :
    1、查看集群状态
    2、配置同步备列表为ANY1(N2),ANY1(N4)
    3、主节点执行业务
    4、同时强制终止异步备节点(N4)cms服务和数据库服务
    5、查看集群状态，查看主节点事务执行情况
    6、恢复参数，恢复环境
Expect      :
    1、集群所有节点状态正常，显示Normal
    2、参数配置成功
    3、事务执行成功
    4、kill异步备节点dms和dn进程成功
    5、cm备节点down掉，dn备节点被拉起，主节点事务不阻塞
    6、恢复参数默认值成功，恢复环境为初始状态成功
History     :
"""

import os
import unittest

from testcase.utils.CommonSH import CommonSH
from testcase.utils.Common import Common
from testcase.utils.Constant import Constant
from testcase.utils.ComThread import ComThread
from testcase.utils.Logger import Logger
from yat.test import Node

Primary_SH = CommonSH('PrimaryDbUser')


@unittest.skipIf(5 != Primary_SH.get_node_num(), '需1主4备环境，否则不执行')
class CmCtl(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.comsh = CommonSH('PrimaryDbUser')
        self.com = Common('PrimaryDbUser')
        self.pri_user = Node('PrimaryDbUser')
        self.constant = Constant()
        self.sync_standby_name = 'synchronous_standby_names'

    def test_cm(self):
        text = '----step1:查看集群状态; expect:集群状态正常,DN主在节点1----'
        self.log.info(text)

        status = self.comsh.exec_cm_ctl('query', '-Cv')
        self.log.info(status)
        self.assertIn("cluster_state   : Normal", status)

        text = '----step2:配置同步备列表为ANY1(N2),ANY1(N4); expect:参数配置成功----'
        self.log.info(text)

        self.default_sync_standby_name = self.com.show_param(self.sync_standby_name)
        self.log.info(self.default_sync_standby_name)
        sql = f"alter system set {self.sync_standby_name} to 'ANY 1(N2), ANY 1(N4)';"
        self.log.info(sql)
        set3 = self.comsh.execut_db_sql(sql)
        self.log.info(set3)
        self.assertIn(self.constant.ALTER_SYSTEM_SUCCESS_MSG, set3, '参数设置失败')

        text = '------step3:主节点执行业务; expect:事务执行成功------'
        self.log.info(text)

        sql_cmd= f"create table {self.table}(id int,name varchar(100));" \
                 f"insert into {self.table} values generate_series(1,1000)," \
                 f"'name_'||generate_series(1,1000);" \
                 f"update {self.table} set name='cm' where id <666;" \
                 f"delete from {self.table} where id > 123;" \
                 f"select count(*) from {self.table};" \
                 f"drop table {self.table} cascade;"
        self.log.info(sql_cmd)

        for i in range(100):
            self.sql_res = ComThread(self.comsh.execut_db_sql, args=(sql_cmd,))
            self.sql_res.setDaemon(True)
            self.sql_res.start()

        count_res1 = self.comsh.execut_db_sql(f'select count(*) from {self.table};')
        self.log.info(count_res1)

        text = '------step4:同时强制终止异步备节点(N4)cms服务和数据库服务  expect:kill异步备节点dms和dn进程成功------'
        self.log.info(text)

        cm_pid = self.com.get_pid(self.pri_user, 'cm_agent')
        self.log.info(cm_pid)

        dn_pid = self.com.get_pid(self.pri_user, 'bin/gaussdb')
        self.log.info(dn_pid)

        kill_cm_cmd = f'kill -9 {cm_pid}'
        kill_cm_res = ComThread(self.com.get_sh_result,
                                args=(self.pri_user, kill_cm_cmd,))
        kill_cm_res.setDaemon(True)
        kill_cm_res.start()

        kill_dn_pid = f'kill -9 {dn_pid}'
        kill_dn_res = ComThread(self.com.get_sh_result,
                                args=(self.pri_user, kill_dn_pid,))
        kill_dn_res.setDaemon(True)
        kill_dn_res.start()

        kill_cm_result = kill_cm_res.get_result()
        self.log.info(kill_cm_result)
        kill_dn_result = kill_dn_res.get_result()
        self.log.info(kill_dn_result)
        self.assertEqual('', kill_cm_result, 'kill cm进程失败')
        self.assertEqual('', kill_dn_result, 'kill dn进程失败')


        text = '------step5:查看集群状态，查看主节点事务执行情况  expect:cm备节点down掉，dn备节点被拉起，主节点事务不阻塞------'
        self.log.info(text)

        status = self.comsh.exec_cm_ctl('query', '-Cv')
        self.log.info(status)
        cm_status = status.split('[   Cluster State   ]')[0]
        dn_status = status.split('[   Cluster State   ]')[1]
        self.assertIn('Down', cm_status, 'cm状态异常')
        self.assertIn('Normal', dn_status, 'dn状态异常')

        count_res2 = self.comsh.execut_db_sql(f'select count(*) from {self.table};')
        self.log.info(count_res2)
        self.assertNotEqual(count_res1.splitlines()[-2], count_res2.splitlines()[-2], '事务阻塞')

    def tearDown(self):
        text = '-----step6:恢复参数默认值，恢复集群初始状态  expect:成功------'
        self.log.info(text)

        reset3 = self.comsh.execute_gsguc('set',
                                          self.constant.GSGUC_SUCCESS_MSG,
                                          f'{self.sync_standby_name}={self.default_sync_standby_name}')
        self.log.info(reset3)

        restart = self.comsh.exec_cm_ctl('stop;', 'cm_ctl start')
        self.log.info(restart)

        status = self.comsh.exec_cm_ctl('query', '-Cv')
        self.log.info(status)
        p_status = status.splitlines()[-1].split('|')[0].split('6001')[-1]
        if 'Primary' in p_status:
            self.log.info('---集群状态正常，无需恢复为初始状态---')
        else:
            recovery = Primary_SH.exec_cm_ctl(mode='switchover', param='-a')
            self.log.info(recovery)

            self.assertIn(self.constant.cm_switchover_success_msg, recovery,
                          '切换失败')

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '状态异常')
        self.assertIn('P Primary Normal',
                      status.splitlines()[-1].split('|')[0].split('6001')[-1],
                      '状态异常')
        self.assertIn('S Standby Normal',
                      status.splitlines()[-1].split('|')[1].split('6002')[-1],
                      '状态异常')
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
